package com.tbit.uqbike.service.business.impl;

import com.tbit.common.utils.TraceUtil;
import com.tbit.uqbike.constant.OperaPswConstant;
import com.tbit.uqbike.constant.WeixinConstant;
import com.tbit.uqbike.enums.SystemCodeEnum;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.pojo.dto.CommonDTO;
import com.tbit.uqbike.object.pojo.statistics.AccountDataMonthSta;
import com.tbit.uqbike.object.pojo.statistics.BrandDataDaySta;
import com.tbit.uqbike.object.pojo.statistics.BrandSerialDaySta;
import com.tbit.uqbike.object.pojo.statistics.MonthDateType;
import com.tbit.uqbike.object.value.LoginInfo;
import com.tbit.uqbike.object.view.JsonResult;
import com.tbit.uqbike.service.business.ReconcileService;
import com.tbit.uqbike.webmanager.dao.core.*;
import com.tbit.uqbike.webmanager.dao.log.RideRefundLogDao;
import com.tbit.uqbike.webmanager.dao.stat.ReconciliationDao;
import com.tbit.uqbike.webmanager.sms.ApiStoreMsgUtils;
import com.tbit.uqbike.webmanager.sms.ClzySmsAuthUtil;
import com.tbit.uqbike.webmanager.util.DateUtils;
import com.tbit.uqbike.webmanager.util.ZipUtils;
import com.tbit.uqbike.webmanager.util.adaPay.AdaPayUtil;
import com.tbit.utils.DateTimeUtil;
import com.tbit.utils.NullUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author HZW
 * @ClassName ReconcileServiceImpl
 * @Description
 * @date 2022/4/2 16:46
 * @Version 1.0
 */
@Slf4j
@Service("ReconcileService")
public class ReconcileServiceImpl implements ReconcileService {
    @Autowired
    private ReconciliationDao reconciliationDao;
    @Autowired
    private AccountDao accountDao;
    @Autowired
    private UserDao userDao;
    @Autowired
    private RechargeDao rechargeDao;
    @Autowired
    private UserAccountLogDao userAccountLogDao;
    @Autowired
    private RideRefundLogDao rideRefundLogDao;
    @Autowired
    private RideLogDao rideLogDao;
    @Autowired
    private SmsAuthConfigDao smsAuthConfigDao;
    @Autowired
    private UsermsgDao usermsgDao;

    public static void main(String[] args) {
        ApiStoreMsgUtils.sendModelSms("13751117243", "b55962a387d4267a0c95168525ae58e0", 92491, "优骑智行",
                "尊敬的用户，您有新的优惠券到账，请登录优骑智行小程序'我的-我的优惠券'查看"
        );
    }

    public Map<String, Object> initialize(Integer accountId, String startTime, String endTime) {
        Map<String, Object> map = new HashMap<>(5);
        map.put("accountId", accountId);
        if (null != startTime && null != endTime) {
            map.put("startTime", startTime);
            map.put("endTime", endTime);
        }
        return map;
    }

    @Override
    public List<Map<String, Object>> getBrandDateByTime(Integer accountId, String startTime, String endTime) throws ParseException {
        Map<String, Object> param = initialize(accountId, startTime, endTime);

        /**获取这个品牌的信息*/
        Account brandAccount = accountDao.getByAccountId(accountId);
        String sdfToDay = new SimpleDateFormat("yyyy-MM").format(new Date());
        List<BrandDataDaySta> brandMonthDate = reconciliationDao.getBrandMonthDate(param);
        List<Map<String, Object>> maps = new LinkedList<>();
        if (!NullUtils.isEmpty(brandMonthDate)) {
            for (BrandDataDaySta brandDataDaySta : brandMonthDate) {
                Map<String, Object> map = new HashMap<>();
                //去除当月的
                if (sdfToDay.equals(brandDataDaySta.getDate())) {
                    continue;
                }
                param.put("startTime", brandDataDaySta.getDate());
                param.put("endTime", DateTimeUtil.getLastMonth(-1, brandDataDaySta.getDate()));
                List<BrandSerialDaySta> serialDayStaList = reconciliationDao.selectSerialDate(param);
                if (!NullUtils.isEmpty(serialDayStaList)) {
                    /**根据类型分组*/
                    Map<Integer, List<BrandSerialDaySta>> dataDayMap = serialDayStaList.stream().collect(Collectors.groupingBy(BrandSerialDaySta::getType));
                    Integer WXSerial = dataDayMap.get(0).get(0).getOrderMoney();
                    map.put("WXSerial", WXSerial);
                    Integer ZFBSerial = dataDayMap.get(1).get(0).getOrderMoney();
                    map.put("ZFBSerial", ZFBSerial);
                    List<BrandSerialDaySta> brandSerialDayStas = dataDayMap.get(2);
                    Integer adaPaySerial = brandSerialDayStas == null ? 0 : brandSerialDayStas.get(0) == null ? 0 : brandSerialDayStas.get(0) == null ? 0 : brandSerialDayStas.get(0).getOrderMoney();
                    map.put("AdaPaySerial", adaPaySerial);


                    map.put("serialTotal", brandDataDaySta.getRideCard() + brandDataDaySta.getVipCard() +
                            brandDataDaySta.getDepositCard() + brandDataDaySta.getCouponOrder()
                            + brandDataDaySta.getRechargeMoney() + brandDataDaySta.getUserCommitPledge() - brandDataDaySta.getRideCardRefund()
                            - brandDataDaySta.getVipCardRefund() - brandDataDaySta.getDepositCardRefund() - brandDataDaySta.getCouponOrderRefund()
                            - brandDataDaySta.getRechargeRefund() - brandDataDaySta.getUserRefundPledge());
                    //map.put("serialTotal", (WXSerial == null ? 0 : WXSerial) + (ZFBSerial == null ? 0 : ZFBSerial) + (adaPaySerial == null ? 0 : adaPaySerial));
                }

                brandDataDaySta.setTotal(brandDataDaySta);
                brandDataDaySta.setUserPledgeMargin(brandDataDaySta);
                brandDataDaySta.setUserBalanceMargin(brandDataDaySta);

                brandDataDaySta.setBrandName(brandAccount.getName());
                map.put("brandMonthDate", brandDataDaySta);
                maps.add(map);
            }
        }
        return maps;
    }

    @Override
    public List<AccountDataMonthSta> getAreaByTime(Integer accountId, String startTime, String endTime) throws ParseException {
        Map<String, Object> param = new HashMap<>(5);
        param.put("brandId", accountId);
        if (null != startTime && null != endTime) {
            param.put("startTime", startTime);
            param.put("endTime", endTime);
        }
        /**获取这个品牌的所有区域*/
        List<Account> list = accountDao.getById(accountId);
        Map<Integer, Account> map = new HashMap<>();
        if (list != null && list.size() > 0) {
            for (Account account : list) {
                map.put(account.getAccountId(), account);
            }
        }
        /**查询符合条件的数据*/
        List<AccountDataMonthSta> accountDataDayStaList = reconciliationDao.getAreaDate(param);
        if (!NullUtils.isEmpty(accountDataDayStaList)) {
            for (AccountDataMonthSta accountDataDaySta : accountDataDayStaList) {
                Account accountSeed = map.get(accountDataDaySta.getAccountId());
                if (!NullUtils.isEmpty(accountSeed)) {
                    /**将区域名称一同设置进去*/
                    accountDataDaySta.setName(accountSeed.getName());
                }
                accountDataDaySta.setTotal(accountDataDaySta);
            }
        }
        return accountDataDayStaList;
    }

    @Override
    public List<Map<String, Object>> getDateByAreaTime(Integer accountId, String dataTime) {
        Map<String, Object> param = new HashMap<>();
        param.put("brandId", accountId);
        param.put("dataTime", dataTime);
        /**获取这个品牌的所有区域*/
        List<Account> list = accountDao.getById(accountId);
        Map<Integer, Account> map = new HashMap<>();
        if (list != null && list.size() > 0) {
            for (Account account : list) {
                map.put(account.getAccountId(), account);
            }
        }

        List<Map<String, Object>> resultDate = new LinkedList<>();

        /**查询品牌下每个区域的总数*/
        List<AccountDataMonthSta> dataMonthSta = reconciliationDao.getAreaDate(param);

        if (!NullUtils.isEmpty(dataMonthSta)) {
            dataMonthSta.forEach(data -> {
                Map<String, Object> resultMap = new HashMap<>();
                data.setTotal(data);
                resultMap.put("total", data.getTotal());
                resultMap.put("monthSta", data);
                param.put("accountId", data.getAccountId());

                Account accountSeed = map.get(data.getAccountId());
                if (!NullUtils.isEmpty(accountSeed)) {
                    /**将区域名称一同设置进去*/
                    resultMap.put("name", accountSeed.getName());
                }

                Map<String, Object> typeList = new HashMap<>();
                List<MonthDateType> monthDateTypes = reconciliationDao.selectDataByArea(param);
                /**根据类型进行分组*/
                Map<Integer, List<MonthDateType>> typeMap = monthDateTypes.stream().collect(Collectors.groupingBy(MonthDateType::getType));
                if (!NullUtils.isEmpty(typeMap)) {
                    typeMap.forEach((typeKey, typeValue) -> {
                        List<Map<String, Object>> mapList = new LinkedList<>();
                        for (MonthDateType monthDateType : typeValue) {
                            Map<String, Object> orderPayData = new HashMap<>();
                            orderPayData.put("month", monthDateType.getClassifyDate());
                            orderPayData.put("value", monthDateType.getMoney());
                            mapList.add(orderPayData);
                        }
                        typeList.put(typeKey.toString(), mapList);
                    });
                    resultMap.put("typeList", typeList);
                }
                resultDate.add(resultMap);
            });
        }
        return resultDate;
    }

    @Override
    public JsonResult refund(Integer accountid, String rideOrderNO, String phone, Integer rideRefundMoney,
                             Integer refundType, Integer isSend, String isMessage, LoginInfo login) throws ParseException {
        Date nowDate = DateUtils.getNowDate();

        /**获取区域上一级的id*/
        Account brand = accountDao.getAgentId(accountid);
        if (NullUtils.isEmpty(brand)) {
            throw new BaseException("区域不存在");
        }
        User user = userDao.getUserByPhone(new CommonDTO(brand.getParentId(), phone));
        if (NullUtils.isEmpty(user)) {
            throw new BaseException(SystemCodeEnum.USER_NOT_EXIST);
        }

        RideLog rideLog1 = rideLogDao.getByOrderNO(rideOrderNO);
        if (NullUtils.isEmpty(rideLog1)) {
            throw new BaseException(SystemCodeEnum.ORDER_DOES_TO_EXIST);
        }

        if (rideRefundMoney > rideLog1.getMoney()) {
            throw new BaseException(SystemCodeEnum.SUPER_RETREAT);
        }


        RideRefundLog refundLog = rideRefundLogDao.selectLog(new RideRefundLog(rideOrderNO));
        if (!NullUtils.isEmpty(refundLog)) {
            if (rideRefundMoney > rideLog1.getMoney() - refundLog.getMoney()) {
                throw new BaseException(SystemCodeEnum.REFUND_MONEY_MORE_RIDE_MONEY);
            }
        }


        boolean Succ = false;
        Integer hasRefundMoney = 0;
        /**退款到余额*/
        if (refundType == 0) {
            try {
                Map<String, Object> map = new HashMap<>();
                map.put("money", rideRefundMoney);
                map.put("userId", user.getUserId());
                map.put("updateTime", nowDate);
                /**退款金额到用户余额中*/
                userDao.updateMoney(map);

                /**记录余额变动日记*/
                UserAccountLog userAccountLog = new UserAccountLog(user.getUserId(), accountid, WeixinConstant.PRACTICAL_MONEY, WeixinConstant.FEE_RECHARGE, rideRefundMoney, nowDate, "原路退还");
                userAccountLogDao.insert(userAccountLog);

                /**添加骑行订单退款*/
                RideRefundLog rideRefundLog = new RideRefundLog(accountid, rideLog1.getOrderNO(), rideRefundMoney, nowDate, user.getUserId(), user.getPhone(), login.getAccountUserId(), login.getPhone(), "原路退还_" + rideLog1.getOrderNO(), 0);
                rideRefundLogDao.insertLog(rideRefundLog);

                Succ = true;
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new BaseException(SystemCodeEnum.OPERATIOBMN_FAILED);
            }
        } else if (refundType == 1) {
            /**原路返回*/
            List<Recharge> rechargeList = rechargeDao.getRecentlyDate(user.getUserId());
            rechargeList.stream().filter
                    (data -> data.getRechargeType() == 0 || data.getRechargeType() == 3);
            /**获取最近的一条充值记录*/
            Recharge recharge = null;
            try {
                recharge = rechargeList.stream().max(Comparator.comparing(Recharge::getRechargeTime)).get();
            } catch (Exception e) {
                throw new BaseException("无充值记录");
            }

            recharge.setRefundMoney(Double.parseDouble(rideRefundMoney.toString()));
            Account parentAccount = accountDao.getAgentId(accountid);
            if (NullUtils.isEmpty(parentAccount)) {
                throw new BaseException("无品牌数据");
            }
            /**获取充值类型*/
            Integer rechargeType = recharge.getRechargeType();
            /**进行数据校验及失效校验*/
            verify(recharge);
            String logStr = "金额部分退款成功,";
            try {
                //调用客户端退款接口
                hasRefundMoney = AdaPayUtil.refund(recharge.getUserId(), rideRefundMoney, rechargeType, rideLog1.getOrderNO(), null);
                if (hasRefundMoney.equals(rideRefundMoney)) {
                    //退款金额等于已退款金额
                    Succ = true;
                    logStr = "金额退款成功";
                } else {
                    log.warn("金额退还失败，商户平台订单号=" + recharge.getOrderNO());
                }
                //已退款金额大于0
                if (hasRefundMoney > 0) {
                    String orderNO = recharge.getOrderNO();
                    log.info(logStr + "商户平台订单号=" + orderNO);
                    Integer userId = recharge.getUserId();
                    /**添加骑行订单退款*/
                    RideRefundLog rideRefundLog = new RideRefundLog(accountid, rideLog1.getOrderNO(), hasRefundMoney, nowDate, user.getUserId(), user.getPhone(), login.getAccountUserId(), login.getPhone(), rideLog1.getOrderNO(), 1);
                    rideRefundLogDao.insertLog(rideRefundLog);
                    //记录个人资金变动
                    UserAccountLog userAccountLog = new UserAccountLog(userId, accountid, 0, 0, hasRefundMoney, nowDate, "原路退还");
                    userAccountLogDao.insert(userAccountLog);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        /**确认发送消息*/
        if (isSend == 1 && Succ) {
            SmsAuthConfig smsAuthConfig = smsAuthConfigDao.selectSmsConfig(brand.getParentId());
            if (NullUtils.isEmpty(isMessage)) {
                isMessage = "你有一笔订单退款,订单金额为[" + rideRefundMoney / 100.0 + "],请前往小程序查看!";
            }
            if (!NullUtils.isEmpty(smsAuthConfig)) {
                /**寻程发送短信*/
                ApiStoreMsgUtils.refundSend(phone, isMessage, smsAuthConfig.getSmsCodeKey(), Integer.valueOf(smsAuthConfig.getModelId()));
            } else {
                Map<String, Integer> mapSMS = new HashMap<>();
                mapSMS.put("accountId", user.getAccountId());
                mapSMS.put("configType", 4);
                Account brandArea = accountDao.getByAccountId(user.getAccountId());
                BrandRemoteConfig brandRemoteConfig = smsAuthConfigDao.getByConfigType(mapSMS);
                if (brandRemoteConfig != null) {
                    String[] strings = brandRemoteConfig.getParamKV().split("&");
                    String accounts = strings[0].substring(strings[0].indexOf("=") + 1);
                    String password = strings[1].substring(strings[1].indexOf("=") + 1);
                    ClzySmsAuthUtil.sendSms(accounts, password, "【" + brandArea.getName() + "】" + isMessage, phone);
                }
            }
            usermsgDao.insertSelective(new Usermsg(null, 0, user.getUserId(), nowDate, null, 0, "骑行订单退款", isMessage, "", ""));
        }

        if (Succ) {
            return JsonResult.ok();
        } else {
            if (hasRefundMoney > 0) {
                return JsonResult.fail("退款异常,实际退款金额为" + String.format("%.2f", ((double) hasRefundMoney / 100D)) + "元", TraceUtil.getTraceIdByLocal());
            } else {
                return JsonResult.fail("退款失败,请联系管理员",TraceUtil.getTraceIdByLocal());
            }
        }

    }

    @Override
    public boolean excel(HttpServletResponse response, OutputStream out, String dataTime, Integer accountId) {
        Account brand = accountDao.getByAccountId(accountId);
        String filePath = "";
        if (!NullUtils.isEmpty(brand)) {
            filePath = OperaPswConstant.EXCEL_PATH + brand.getName() + "/" + dataTime;
        } else {
            throw new BaseException(SystemCodeEnum.NOT_EXIST);
        }
        boolean flag = true;

        try {
            ZipUtils.toZip(filePath, out, true);
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }


    public void verify(Recharge recharge) throws ParseException {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        /**微信退款判断订单的时效性*/
        if (recharge.getType() == 1 || recharge.getType() == 2) {
            if (DateUtils.MoreThenMonth(new Date(), formatter.parse(recharge.getPayTime()), 12)) {
                throw new BaseException("充值订单时间大于一年,无法退款");
            }
        }
        /**支付宝退款判断订单的时效性*/
        if (recharge.getType() == 3 || recharge.getType() == 5) {
            if (DateUtils.MoreThenMonth(new Date(), formatter.parse(recharge.getPayTime()), 3)) {
                throw new BaseException("充值订单时间大于三个月,无法退款");
            }
        }
        /**汇付支付退款判断订单的时效性*/
        if (recharge.getType() == 7 || recharge.getType() == 8) {
            if (DateUtils.MoreThenMonth(new Date(), formatter.parse(recharge.getPayTime()), 6)) {
                throw new BaseException("充值订单时间大于六个月,无法退款");
            }
        }
    }
}
